/*-------------------------------------------------------------------------
 *
 * tupdesc.h
 *	  POSTGRES 元组描述符定义。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/access/tupdesc.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef TUPDESC_H
#define TUPDESC_H

#include "access/attnum.h"
#include "catalog/pg_attribute.h"
#include "nodes/pg_list.h"


typedef struct AttrDefault
{
	AttrNumber	adnum;
	char	   *adbin;			/* expr 的 nodeToString 表示 */
} AttrDefault;

typedef struct ConstrCheck
{
	char	   *ccname;
	char	   *ccbin;			/* expr 的 nodeToString 表示 */
	bool		ccvalid;
	bool		ccnoinherit;	/* 这是一个不可继承的约束 */
} ConstrCheck;

/* 该结构包含一个元组的约束 */
typedef struct TupleConstr
{
	AttrDefault *defval;		/* array */
	ConstrCheck *check;			/* array */
	struct AttrMissing *missing;	/* 缺失的属性值，如果没有则为 NULL */
	uint16		num_defval;
	uint16		num_check;
	bool		has_not_null;
	bool		has_generated_stored;
} TupleConstr;

/*
 * 该结构在后端中传递，以描述元组的结构。
 * 对于来自磁盘关系的元组，信息是从 pg_attribute、pg_attrdef 和 pg_constraint
 * 目录中收集的。瞬态行类型（如连接查询结果）具有匿名的
 * TupleDesc 结构，通常省略任何约束信息；因此，该结构的设计允许有效地省略约束。
 *
 * 注意，只有用户属性，而不是系统属性，在 TupleDesc 中被提及。
 *
 * 如果 tupdesc 被知晓对应于某个命名行类型（如表的行类型），
 * 则 tdtypeid 标识该类型，tdtypmod 为 -1。否则
 * tdtypeid 为 RECORDOID，tdtypmod 可以是 -1 表示完全匿名的
 * 行类型，或大于等于 0 的值以允许在 typcache.c 类型缓存中查找行类型。
 *
 * 注意，tdtypeid 永远不是复合类型域的 OID，即使我们处理的值
 * 在某个更高层级上已知为复合类型域的值。这是因为 tdtypeid/tdtypmod 需要
 * 与复合 Datum 的类型标记相匹配，而这些也从不明确标记为域类型。
 *
 * 存在于缓存中（当前为 relcache 或 typcache）的元组描述符
 * 是引用计数的：当其引用计数为零时，可以删除它们。然而，执行器创建的元组描述符
 * 不需要引用计数：它们仅在适当的内存上下文中创建，并在上下文释放时消失。
 * 我们将这种描述符的 tdrefcount 字段设置为 -1，而引用计数的描述符
 * 总是 tdrefcount >= 0。
 */
typedef struct TupleDescData
{
	int			natts;			/* 元组中的属性数量 */
	Oid			tdtypeid;		/* 元组类型的复合类型 ID */
	int32		tdtypmod;		/* 元组类型的 typmod */
	int			tdrefcount;		/* 引用计数，或 -1 表示不计数 */
	TupleConstr *constr;		/* 约束，如果没有则为 NULL */
	/* attrs[N] 是属性编号 N+1 的描述 */
	FormData_pg_attribute attrs[FLEXIBLE_ARRAY_MEMBER];
}			TupleDescData;
typedef struct TupleDescData *TupleDesc;

/* tupdesc 的第 i 个属性的访问器。 */
#define TupleDescAttr(tupdesc, i) (&(tupdesc)->attrs[(i)])

extern TupleDesc CreateTemplateTupleDesc(int natts);

extern TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs);

extern TupleDesc CreateTupleDescCopy(TupleDesc tupdesc);

extern TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc);

#define TupleDescSize(src) \
	(offsetof(struct TupleDescData, attrs) + \
	 (src)->natts * sizeof(FormData_pg_attribute))

extern void TupleDescCopy(TupleDesc dst, TupleDesc src);

extern void TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
							   TupleDesc src, AttrNumber srcAttno);

extern void FreeTupleDesc(TupleDesc tupdesc);

extern void IncrTupleDescRefCount(TupleDesc tupdesc);
extern void DecrTupleDescRefCount(TupleDesc tupdesc);

#define PinTupleDesc(tupdesc) \
	do { \
		if ((tupdesc)->tdrefcount >= 0) \
			IncrTupleDescRefCount(tupdesc); \
	} while (0)

#define ReleaseTupleDesc(tupdesc) \
	do { \
		if ((tupdesc)->tdrefcount >= 0) \
			DecrTupleDescRefCount(tupdesc); \
	} while (0)

extern bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);

extern uint32 hashTupleDesc(TupleDesc tupdesc);

extern void TupleDescInitEntry(TupleDesc desc,
							   AttrNumber attributeNumber,
							   const char *attributeName,
							   Oid oidtypeid,
							   int32 typmod,
							   int attdim);

extern void TupleDescInitBuiltinEntry(TupleDesc desc,
									  AttrNumber attributeNumber,
									  const char *attributeName,
									  Oid oidtypeid,
									  int32 typmod,
									  int attdim);

extern void TupleDescInitEntryCollation(TupleDesc desc,
										AttrNumber attributeNumber,
										Oid collationid);

extern TupleDesc BuildDescForRelation(List *schema);

extern TupleDesc BuildDescFromLists(List *names, List *types, List *typmods, List *collations);

#endif							/* TUPDESC_H */
